/*
OpenMVL Matrix Vector Library
Copyright (c) 2009 FluidInteractive (R)
 
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising
from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
 
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must
not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
 
Written by: Nicola Candussi <nicola@fluidinteractive.com>
*/

//tutorial2.hpp
// 
//here there are some other features of OpenMVL, please refer to tutorial.hpp 
// for a quickstart

#ifndef MVL_EXAMPLES_TUTORIAL2_HPP
#define MVL_EXAMPLES_TUTORIAL2_HPP

//this tutorial builds on top of the first
#include "tutorial.hpp"

namespace mvl {

namespace examples {

//this defines make the declaration a little more compact:
#define e layout::e
#define _0_ layout::_0_
#define _1_ layout::_1_
#define _v_ layout::_v_

//declare a 4x1 column vector. We'll use it to represent direction in 3d space, so it the 4th component 
//is always 0 (the corresponding entry doesn't need to be explicitly specified)
typedef layout::make_sparse <
    4, 1, 
    layout::column_major_tag,
    meta::vector<
        meta::ivector<0, 1, 2> 
    >
>::type vector_layout_t;
//Note that alternatively, instead of meta::ivector<0, 1, 2> we could have used
//meta::vector< e<0, _v_>, e<1, _v_>, e<2, _v_> > or even
//meta::vector< e<0, _v_>, e<1, _v_>, e<2, _v_>, e<3, _0_> > but the declaration with
//meta::ivector is more compact

#undef e
#undef _0_
#undef _1_
#undef _v_

struct vector_t : public mat<float, vector_layout_t> 
{
    typedef mat<float, vector_layout_t>  parent_t;
    typedef float                       value_type;

    //constructors (needed)
    //using parent_type::vector_t; in c++0x
    vector_t() : parent_t() {  }

    vector_t(const vector_t &p) : parent_t(p) { }

    template<typename E>
    vector_t(const expr<E>& e) : parent_t(e) {  }

    vector_t(float v0, float v1, float v2, float v3 = 0.0) : parent_t(v0, v1, v2) {  }

    //inherit operator =
    using parent_t::operator =;

    //some useful access
    float x() const { return parent_t::operator()(0); }
    float& x() { return parent_t::operator()(0); }

    float y() const { return parent_t::operator()(1); }
    float& y() { return parent_t::operator()(1); }

    float z() const { return parent_t::operator()(2); }
    float& z() { return parent_t::operator()(2); }

    float w() const { return float(0.0); }
};


void tutorial2(int argc, char* argv[])
{
    std::cout << "tutorial2" << std::endl;

    //init some vectors
    vector_t v0(1, 1, 2);

    //comma initializer
    vector_t v1;
    assign(v1) = 1, 2, 3;

    //copy constructor
    vector_t v2(v1);

    //dot product
    float d = dot(v0, v1);

    //cross product
    v2 = cross(v0, v1); 

    //length
    float l = norm_2(v0);

    //normalize
    v2 = normalize(v0);

    //use the same 4x4 matrix defined in tutorial.hpp for transforming points to transform the direction vector
    matrix_t m0;
    v2 = prod(m0, v0);
}

} // namespace examples

} // namespace mvl

#endif
